package com.blog.blog.service.impl;

import com.blog.blog.service.SystemMonitorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

/**
 * 系统监控服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SystemMonitorServiceImpl implements SystemMonitorService {
    
    private final DataSource dataSource;
    private final StringRedisTemplate stringRedisTemplate;
    
    @Override
    public Map<String, Object> getSystemInfo() {
        Map<String, Object> systemInfo = new HashMap<>();
        
        try {
            OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
            RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
            
            systemInfo.put("osName", osBean.getName());
            systemInfo.put("osVersion", osBean.getVersion());
            systemInfo.put("osArch", osBean.getArch());
            systemInfo.put("availableProcessors", osBean.getAvailableProcessors());
            systemInfo.put("systemLoadAverage", osBean.getSystemLoadAverage());
            systemInfo.put("javaVersion", System.getProperty("java.version"));
            systemInfo.put("javaVendor", System.getProperty("java.vendor"));
            systemInfo.put("javaHome", System.getProperty("java.home"));
            systemInfo.put("userDir", System.getProperty("user.dir"));
            systemInfo.put("uptime", runtimeBean.getUptime());
            systemInfo.put("startTime", runtimeBean.getStartTime());
            
        } catch (Exception e) {
            log.error("获取系统信息失败", e);
            systemInfo.put("error", e.getMessage());
        }
        
        return systemInfo;
    }
    
    @Override
    public Map<String, Object> getJvmInfo() {
        Map<String, Object> jvmInfo = new HashMap<>();
        
        try {
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
            
            // 内存信息
            long heapUsed = memoryBean.getHeapMemoryUsage().getUsed();
            long heapMax = memoryBean.getHeapMemoryUsage().getMax();
            long heapCommitted = memoryBean.getHeapMemoryUsage().getCommitted();
            long nonHeapUsed = memoryBean.getNonHeapMemoryUsage().getUsed();
            long nonHeapMax = memoryBean.getNonHeapMemoryUsage().getMax();
            long nonHeapCommitted = memoryBean.getNonHeapMemoryUsage().getCommitted();
            
            jvmInfo.put("heapUsed", heapUsed);
            jvmInfo.put("heapMax", heapMax);
            jvmInfo.put("heapCommitted", heapCommitted);
            jvmInfo.put("heapUsedPercent", heapMax > 0 ? (double) heapUsed / heapMax * 100 : 0);
            jvmInfo.put("nonHeapUsed", nonHeapUsed);
            jvmInfo.put("nonHeapMax", nonHeapMax);
            jvmInfo.put("nonHeapCommitted", nonHeapCommitted);
            
            // JVM参数
            jvmInfo.put("jvmArguments", runtimeBean.getInputArguments());
            jvmInfo.put("vmName", runtimeBean.getVmName());
            jvmInfo.put("vmVersion", runtimeBean.getVmVersion());
            jvmInfo.put("vmVendor", runtimeBean.getVmVendor());
            
            // 线程信息
            jvmInfo.put("threadCount", ManagementFactory.getThreadMXBean().getThreadCount());
            jvmInfo.put("peakThreadCount", ManagementFactory.getThreadMXBean().getPeakThreadCount());
            jvmInfo.put("daemonThreadCount", ManagementFactory.getThreadMXBean().getDaemonThreadCount());
            
            // GC信息
            jvmInfo.put("gcCollectors", ManagementFactory.getGarbageCollectorMXBeans().stream()
                .map(gc -> Map.of(
                    "name", gc.getName(),
                    "collectionCount", gc.getCollectionCount(),
                    "collectionTime", gc.getCollectionTime()
                )).toList());
                
        } catch (Exception e) {
            log.error("获取JVM信息失败", e);
            jvmInfo.put("error", e.getMessage());
        }
        
        return jvmInfo;
    }
    
    @Override
    public Map<String, Object> getDatabaseInfo() {
        Map<String, Object> dbInfo = new HashMap<>();
        
        try (Connection connection = dataSource.getConnection()) {
            dbInfo.put("connected", true);
            dbInfo.put("url", connection.getMetaData().getURL());
            dbInfo.put("driverName", connection.getMetaData().getDriverName());
            dbInfo.put("driverVersion", connection.getMetaData().getDriverVersion());
            dbInfo.put("databaseProductName", connection.getMetaData().getDatabaseProductName());
            dbInfo.put("databaseProductVersion", connection.getMetaData().getDatabaseProductVersion());
            dbInfo.put("autoCommit", connection.getAutoCommit());
            dbInfo.put("readOnly", connection.isReadOnly());
            dbInfo.put("transactionIsolation", connection.getTransactionIsolation());
            
        } catch (Exception e) {
            log.error("获取数据库信息失败", e);
            dbInfo.put("connected", false);
            dbInfo.put("error", e.getMessage());
        }
        
        return dbInfo;
    }
    
    @Override
    public Map<String, Object> getRedisInfo() {
        Map<String, Object> redisInfo = new HashMap<>();
        
        try {
            // 测试Redis连接
            stringRedisTemplate.opsForValue().set("health_check", "ok", 10, java.util.concurrent.TimeUnit.SECONDS);
            String value = stringRedisTemplate.opsForValue().get("health_check");
            
            redisInfo.put("connected", "ok".equals(value));
            
            // 获取Redis信息
            try {
                String info = stringRedisTemplate.execute((org.springframework.data.redis.core.RedisCallback<String>) connection -> connection.info().toString());
                
                if (info != null) {
                    String[] lines = info.split("\r\n");
                    for (String line : lines) {
                        if (line.startsWith("redis_version:")) {
                            redisInfo.put("version", line.substring("redis_version:".length()));
                        } else if (line.startsWith("used_memory_human:")) {
                            redisInfo.put("usedMemory", line.substring("used_memory_human:".length()));
                        } else if (line.startsWith("connected_clients:")) {
                            redisInfo.put("connectedClients", Integer.parseInt(line.substring("connected_clients:".length())));
                        } else if (line.startsWith("uptime_in_seconds:")) {
                            redisInfo.put("uptime", Long.parseLong(line.substring("uptime_in_seconds:".length())));
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("获取Redis详细信息失败", e);
            }
            
        } catch (Exception e) {
            log.error("获取Redis信息失败", e);
            redisInfo.put("connected", false);
            redisInfo.put("error", e.getMessage());
        }
        
        return redisInfo;
    }
    
    @Override
    public Map<String, Object> getDiskInfo() {
        Map<String, Object> diskInfo = new HashMap<>();
        
        try {
            File root = new File("/");
            long totalSpace = root.getTotalSpace();
            long freeSpace = root.getFreeSpace();
            long usedSpace = totalSpace - freeSpace;
            
            diskInfo.put("totalSpace", totalSpace);
            diskInfo.put("freeSpace", freeSpace);
            diskInfo.put("usedSpace", usedSpace);
            diskInfo.put("usedPercent", totalSpace > 0 ? (double) usedSpace / totalSpace * 100 : 0);
            
            // 获取当前工作目录的磁盘信息
            File workDir = new File(System.getProperty("user.dir"));
            diskInfo.put("workDirTotalSpace", workDir.getTotalSpace());
            diskInfo.put("workDirFreeSpace", workDir.getFreeSpace());
            diskInfo.put("workDirUsedSpace", workDir.getTotalSpace() - workDir.getFreeSpace());
            
        } catch (Exception e) {
            log.error("获取磁盘信息失败", e);
            diskInfo.put("error", e.getMessage());
        }
        
        return diskInfo;
    }
    
    @Override
    public Map<String, Object> checkHealth() {
        Map<String, Object> health = new HashMap<>();
        boolean overall = true;
        
        // 检查JVM内存
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        long heapUsed = memoryBean.getHeapMemoryUsage().getUsed();
        long heapMax = memoryBean.getHeapMemoryUsage().getMax();
        double heapUsedPercent = heapMax > 0 ? (double) heapUsed / heapMax * 100 : 0;
        
        boolean memoryHealthy = heapUsedPercent < 90;
        health.put("memory", Map.of(
            "healthy", memoryHealthy,
            "usedPercent", heapUsedPercent,
            "message", memoryHealthy ? "内存使用正常" : "内存使用过高"
        ));
        overall = overall && memoryHealthy;
        
        // 检查数据库连接
        boolean dbHealthy = false;
        try (Connection connection = dataSource.getConnection()) {
            dbHealthy = connection.isValid(5);
        } catch (Exception e) {
            log.error("数据库健康检查失败", e);
        }
        health.put("database", Map.of(
            "healthy", dbHealthy,
            "message", dbHealthy ? "数据库连接正常" : "数据库连接异常"
        ));
        overall = overall && dbHealthy;
        
        // 检查Redis连接
        boolean redisHealthy = false;
        try {
            stringRedisTemplate.opsForValue().set("health_check", "ok", 5, java.util.concurrent.TimeUnit.SECONDS);
            redisHealthy = "ok".equals(stringRedisTemplate.opsForValue().get("health_check"));
        } catch (Exception e) {
            log.error("Redis健康检查失败", e);
        }
        health.put("redis", Map.of(
            "healthy", redisHealthy,
            "message", redisHealthy ? "Redis连接正常" : "Redis连接异常"
        ));
        overall = overall && redisHealthy;
        
        // 检查磁盘空间
        File root = new File("/");
        long totalSpace = root.getTotalSpace();
        long freeSpace = root.getFreeSpace();
        double freePercent = totalSpace > 0 ? (double) freeSpace / totalSpace * 100 : 0;
        boolean diskHealthy = freePercent > 10;
        
        health.put("disk", Map.of(
            "healthy", diskHealthy,
            "freePercent", freePercent,
            "message", diskHealthy ? "磁盘空间充足" : "磁盘空间不足"
        ));
        overall = overall && diskHealthy;
        
        health.put("overall", overall);
        health.put("timestamp", System.currentTimeMillis());
        
        return health;
    }
    
    @Override
    public Map<String, Object> getPerformanceMetrics() {
        Map<String, Object> metrics = new HashMap<>();
        
        try {
            // CPU使用率
            OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
            if (osBean instanceof com.sun.management.OperatingSystemMXBean sunOsBean) {
                metrics.put("processCpuLoad", sunOsBean.getProcessCpuLoad() * 100);
                metrics.put("systemCpuLoad", sunOsBean.getSystemCpuLoad() * 100);
                metrics.put("totalPhysicalMemory", sunOsBean.getTotalPhysicalMemorySize());
                metrics.put("freePhysicalMemory", sunOsBean.getFreePhysicalMemorySize());
                metrics.put("committedVirtualMemory", sunOsBean.getCommittedVirtualMemorySize());
            }
            
            // 系统负载
            metrics.put("systemLoadAverage", osBean.getSystemLoadAverage());
            
            // JVM性能指标
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            metrics.put("heapMemoryUsage", memoryBean.getHeapMemoryUsage());
            metrics.put("nonHeapMemoryUsage", memoryBean.getNonHeapMemoryUsage());
            
            // 线程信息
            metrics.put("threadCount", ManagementFactory.getThreadMXBean().getThreadCount());
            metrics.put("peakThreadCount", ManagementFactory.getThreadMXBean().getPeakThreadCount());
            
            // GC信息
            metrics.put("gcInfo", ManagementFactory.getGarbageCollectorMXBeans().stream()
                .map(gc -> Map.of(
                    "name", gc.getName(),
                    "collectionCount", gc.getCollectionCount(),
                    "collectionTime", gc.getCollectionTime()
                )).toList());
            
            // 运行时间
            RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
            metrics.put("uptime", runtimeBean.getUptime());
            
            metrics.put("timestamp", System.currentTimeMillis());
            
        } catch (Exception e) {
            log.error("获取性能指标失败", e);
            metrics.put("error", e.getMessage());
        }
        
        return metrics;
    }
}
